﻿#if NETSTANDARD
using Microsoft.Extensions.Options;
#endif
using PaySharp.Core;
using PaySharp.Core.Exceptions;
using PaySharp.Core.Request;
using PaySharp.Core.Response;
using PaySharp.Core.Utils;
using PaySharp.Wechatpay.Request;
using PaySharp.Wechatpay.Response;
using System;
using System.Threading.Tasks;
using static PaySharp.Wechatpay.Response.QueryResponse;

namespace PaySharp.Wechatpay
{
    /// <summary>
    /// 微信支付网关
    /// </summary>
    public sealed class WechatpayGateway : BaseGateway
    {
        #region 私有字段

        private readonly Merchant _merchant;

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化微信支付网关
        /// </summary>
        /// <param name="merchant">商户数据</param>
        public WechatpayGateway(Merchant merchant)
            : base(merchant)
        {
            _merchant = merchant;
        }

#if NETSTANDARD

        /// <summary>
        /// 初始化微信支付网关
        /// </summary>
        /// <param name="merchant">商户数据</param>
        public WechatpayGateway(IOptions<Merchant> merchant)
            : this(merchant.Value)
        {
        }

#endif

        #endregion

        #region 属性

        public override string GatewayUrl { get; set; } = "https://api.mch.weixin.qq.com";

        public new Merchant Merchant => _merchant;


        protected override string[] NotifyVerifyParameter => new string[]
        {
            "appid", "return_code", "mch_id", "nonce_str"
        };

        #endregion

        #region 方法


        public override NotifyResult ValidateNotify()
        {
            NotifyResult result = new NotifyResult();
            GatewayData gatewayData = NotifyProcess.ReadNotifyData();
            var response = gatewayData.ToObject<NotifyResponse>(StringCase.Snake);
          
            result.Source = HttpUtil.RequestType == "GET" ? NotifySource.Sync : NotifySource.Async;
            result.Type = NotifyType.UnknownNotify;

            if (response.ReturnCode != "SUCCESS")
            {
                result.Status = NotifyStatus.UnknowError;
            }
            else
            {
                if (response.ResultCode == "SUCCESS" && !string.IsNullOrEmpty(response.TradeType))
                {
                    result.Type = NotifyType.PaySuccess;
                }
                else if (response.RefundStatus == "SUCCESS")
                {
                    result.Type = NotifyType.RefundSuccess;
                }
                if (string.IsNullOrEmpty(response.ReqInfo))
                { 
                    response.Coupons = ConvertUtil.ToList<CouponResponse, object>(gatewayData, -1);
                    if (response.Sign != SubmitProcess.BuildSign(gatewayData, _merchant.Key))
                    {
                        result.Status = NotifyStatus.ValidateError;
                    }
                    else {
                        result.Status = NotifyStatus.ValidateSuccess;
                    }
                }
                else
                {
                    var key = EncryptUtil.MD5(_merchant.Key).ToLower();
                    var data = EncryptUtil.AESDecrypt(response.ReqInfo, key);
                    gatewayData.Clear();
                    gatewayData.FromXml(data);
                    response = gatewayData.ToObject<NotifyResponse>(StringCase.Snake);
                    gatewayData.Add(response, StringCase.Snake);
                    result.Status = NotifyStatus.ValidateSuccess;
                }
                result.Response = response;
            } 
            return result;

        }
         
        protected override void WriteSuccessFlag()
        {
            GatewayData gatewayData = new GatewayData();
            gatewayData.Add("return_code", "SUCCESS");
            HttpUtil.Write(gatewayData.ToXml());
        }

        protected override void WriteFailureFlag()
        {
            GatewayData gatewayData = new GatewayData();
            gatewayData.Add("return_code", "FAIL");
            HttpUtil.Write(gatewayData.ToXml());
        }

        public override TResponse Execute<TModel, TResponse>(Request<TModel, TResponse> request)
        {
            if (request is OAuthRequest)
            {
                return SubmitProcess.AuthExecute(_merchant, request, GatewayUrl);
            }

            return SubmitProcess.Execute(_merchant, request, GatewayUrl);
        }

        #endregion
    }
}
